package com.lap.framework.junit.domain.generator;

import static com.lap.framework.junit.shared.tool.Constant.*;

import com.lap.framework.common.tool.Named;
import com.lap.framework.junit.domain.ClassInfo;
import com.lap.framework.junit.domain.methods.MethodContext;
import com.lap.framework.junit.domain.valueobject.JMethod;
import com.lap.framework.junit.shared.tool.Constant;
import com.lap.framework.junit.shared.tool.Message;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang3.StringUtils;

public abstract class TestFileBuilder {

  public abstract void builderPackage(ClassInfo classInfo);

  public abstract void builderImport();

  public abstract void builderClassHeader(ClassInfo classInfo);

  public abstract void builderClass(ClassInfo classInfo);

  public abstract String getContent();

  public static class Default extends TestFileBuilder {
    private final StringBuilder builder = new StringBuilder(512);

    @Override
    public void builderPackage(ClassInfo classInfo) {
      builder.append(formatter(Message.PACKAGE, classInfo.getPackageName(), WRAP2));
    }

    @Override
    public void builderImport() {
      builder.append(String.join(WRAP, Message.UTIL_LIST)).append(WRAP2);
      builder.append(String.join(WRAP, Message.MOCK_LIST)).append(WRAP2);
      builder.append(String.join(WRAP, Message.JUNIT_LIST)).append(WRAP2);
      builder.append(String.join(WRAP, Message.ENTITY_LIST)).append(WRAP2);
      builder.append(String.join(WRAP, Message.REQUEST_LIST)).append(WRAP2);
      builder.append(String.join(WRAP, Message.MEDIA_TYPE_LIST)).append(WRAP2);
    }

    @Override
    public void builderClassHeader(ClassInfo classInfo) {
      builder.append(formatter(Message.DISPLAY_NAME, EMPTY, classInfo.getRemark(), WRAP));
      builder.append(formatter(Message.METHOD_ORDER, WRAP));
    }

    @Override
    public void builderClass(ClassInfo classInfo) {
      String method = getMethod(classInfo);
      String result =
          formatter(Message.CLASS_BEFORE, Named.upperHump(classInfo.getFileName()))
              + supperClass(classInfo)
              + formatter(Message.ClASS_CONTEXT, WRAP2, method, EMPTY, WRAP);
      builder.append(result);
    }

    @Override
    public String getContent() {
      return builder.toString();
    }

    private String formatter(String pattern, Object... objects) {
      return String.format(pattern, objects);
    }

    private String getMethod(ClassInfo classInfo) {
      StringBuilder result = new StringBuilder(128);

      AtomicInteger count = new AtomicInteger(0);
      classInfo
          .getMethods()
          .forEach(
              method -> {
                String methodContent = new MethodContext().execute(method);
                if (StringUtils.isNotBlank(methodContent)) {
                  result.append(methodHeader(method, count.incrementAndGet()));
                  result.append(getCvs(method));

                  String paramContent = getArgs(method);
                  String testContent = formatterMethod(method, paramContent, methodContent);
                  result.append(testContent);

                  String aggregatorContent = getAggregateContent(method);
                  result.append(getAggregatorClass(method, aggregatorContent));
                }
              });
      return result.toString();
    }

    // @formatter on
    private String formatterMethod(JMethod methodInfo, String args, String content) {
      return formatter(
          Message.TEST_METHOD,
          TAB,
          Named.upperHump(methodInfo.getName()),
          args,
          WRAP,
          content,
          TAB,
          WRAP2);
    }

    private String getArgs(JMethod methodInfo) {
      return methodInfo.isArgMap()
          ? formatter(Message.AGGREGATE, Named.upperHump(methodInfo.getName()))
          : getNormalParam(methodInfo);
    }

    // @formatter off

    private String getNormalParam(JMethod methodInfo) {
      StringBuilder result = new StringBuilder();
      methodInfo
          .getFields()
          .forEach(
              item -> {
                result
                    .append(item.getClazz().getSimpleName())
                    .append(Constant.EMPTY2)
                    .append(item.getDataName())
                    .append(", ");
              });
      result.append(Constant.INTEGER).append(Constant.EMPTY2).append(Constant.RESULT_CODE);

      return result.toString();
    }

    // @ formatter on
    private String getAggregatorClass(JMethod methodInfo, String content) {
      return methodInfo.isArgMap()
          ? formatter(
              Message.INNER_CLASS,
              TAB,
              Named.upperHump(methodInfo.getName()),
              WRAP2,
              content,
              TAB,
              WRAP2)
          : "";
    }

    private String getCvs(JMethod method) {
      Object[] args = new Object[] {TAB, method.getCsvPath(), method.getName(), WRAP};
      return method.isArgMap() ? formatter(Message.CVS_FILE, args) : getCsvSource(method);
    }

    // @ formatter off

    private String getCsvSource(JMethod method) {
      StringBuilder sb = new StringBuilder(32);
      method.getFields().forEach(item -> sb.append(", "));
      return formatter(Message.CVS_SOURCE, TAB, sb, WRAP);
    }

    // @ formatter on
    private String getAggregateContent(JMethod methodInfo) {
      StringBuilder sb = new StringBuilder(128);

      sb.append(formatter(Message.ENTITY_ARRAY, TAB4, (methodInfo.getFields().size() + 1), WRAP));
      AtomicInteger index = new AtomicInteger(0);
      methodInfo
          .getFields()
          .forEach(
              item -> {
                Object[] args =
                    new Object[] {
                      TAB4,
                      index.getAndIncrement(),
                      item.getDataName(),
                      item.getClazz().getSimpleName(),
                      WRAP
                    };
                sb.append(formatter(Message.ENTITY_INDEX, args));
              });
      sb.append(
          formatter(
              Message.ENTITY_INDEX, TAB4, index.getAndIncrement(), "resultCode", "Integer", WRAP));
      sb.append(formatter(Message.ENTITY_UTIL, TAB4, WRAP));

      return formatter(Message.OVERRIDE, TAB2, WRAP)
          + formatter(Message.AGGREGATE_CONTENT, TAB2, WRAP, sb.toString(), TAB2, WRAP2);
    }

    // @ formatter off

    private String methodHeader(JMethod methodInfo, Integer orders) {
      return formatter(Message.DISPLAY_NAME, TAB, methodInfo.getRemark(), WRAP)
          + formatter(Message.ORDER, TAB, orders, WRAP)
          + formatter(Message.PARAMETER_TEST, TAB, WRAP);
    }

    /**
     * 获取超级类
     *
     * @param classInfo 类型信心
     * @return 类型字符串
     */
    private String supperClass(ClassInfo classInfo) {
      return StringUtils.isNotBlank(classInfo.getSupperClass())
          ? " extends " + classInfo.getSupperClass()
          : "";
    }
  }
}
